package com.ds.security.filter;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponseBody;
import com.aliyun.tea.TeaException;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiUserGetuserinfoRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.response.OapiUserGetuserinfoResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.ds.common.jwt.JwtHelper;
import com.ds.common.result.ResponseUtil;
import com.ds.common.result.Result;
import com.ds.common.result.ResultCodeEnum;
import com.ds.model.vo.LoginVo;
import com.ds.security.constant.SysConstants;
import com.ds.security.custom.CustomUserDin;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
//@Configuration
//@Component
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

//    @Resource
    private RedisTemplate redisTemplate;

//    @Resource
    StringRedisTemplate stringRedisTemplate;

    SysConstants sysConstants;


    //构造方法
    public TokenLoginFilter(AuthenticationManager authenticationManager,
                            RedisTemplate redisTemplate,SysConstants sysConstants, StringRedisTemplate stringRedisTemplate) {
        this.setAuthenticationManager(authenticationManager);
        this.setPostOnly(false); //配置其他方式
        this.redisTemplate = redisTemplate;
        this.stringRedisTemplate = stringRedisTemplate;
        this.sysConstants = sysConstants;
        //指定登录接口及提交方式，可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
    }

    //登录认证
    //获取输入的用户名和密码，调用方法认证
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response)
            throws AuthenticationException {
        try {

            //获取用户信息  以流的方式进行获取 并转换为 LoginVo 类型
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);

            // 获取access_token，注意正式代码要有异常流处理
            String access_token= sysConstants.getAPP_ACCESS_TOKEN();
            // 获取用户信息
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getuserinfo");
            OapiUserGetuserinfoRequest requesthttp = new OapiUserGetuserinfoRequest();
            requesthttp.setCode(loginVo.getDinCode());
            requesthttp.setHttpMethod("GET");
            OapiUserGetuserinfoResponse responseHttp;
            try {
                responseHttp = client.execute(requesthttp, access_token);
            } catch (ApiException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
            // 查询得到当前用户的userId
            // 获得到userId之后应用应该处理应用自身的登录会话管理（session）,避免后续的业务交互（前端到应用服务端）每次都要重新获取用户身份，提升用户体验
            String userId = responseHttp.getUserid();
            String user = getUser(userId);
            Map<String, Object> userInfo = JSONUtil.toBean(user, new TypeReference<Map<String, Object>>() {
            }, false);
            String phone = userInfo.get("mobile").toString();
            System.out.println(user);
            System.out.println(phone);


            loginVo.setPhone(phone);

            //封装对象  要封装为 这个类型的 Authentication
            Authentication authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginVo.getPhone(), null);
            //调用方法  就会调用security 中的方法进行认证
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    //认证成功调用方法
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication auth)
            throws IOException, ServletException {
        //获取当前用户
        CustomUserDin customUser = (CustomUserDin)auth.getPrincipal();
        System.out.println(customUser);
//        //生成token
        String token = JwtHelper.createToken(Long.valueOf(customUser.getDsUserEntity().getId()),
                customUser.getDsUserEntity().getUsername());
//
//        //获取当前用户权限数据，放到Redis里面 key：username   value：权限数据
//        redisTemplate.opsForValue().set(customUser.getUsername(),
//                JSON.toJSONString(customUser.getAuthorities()));
//
//        //返回
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("user",customUser.getDsUserEntity());
        ResponseUtil.out(response, Result.ok(map));
    }

    //认证失败调用方法
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed)
            throws IOException, ServletException {
        ResponseUtil.out(response,Result.build(null, ResultCodeEnum.LOGIN_ERROR));
    }


    public String getUser(String userid) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            req.setUserid(userid);
            req.setLanguage("zh_CN");
            OapiV2UserGetResponse rsp = client.execute(req,sysConstants.getAPP_ACCESS_TOKEN());
            System.out.println(rsp.getBody());
            Map<String, Object> res = JSONUtil.toBean(rsp.getBody(), new TypeReference<Map<String, Object>>() {
            }, false);
            return JSONUtil.toJsonStr(res.get("result"));
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return "";
    }

}
